package cc.verywell.pureblock.msg.nfs.map;

import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import cc.verywell.pureblock.func.node.KeyShell;
import cc.verywell.pureblock.log.Pblog;

/**
* 
* Copyright © 2019 TanYaqiu. All rights reserved.
* @author TanYaqiu 
* @address flat 601
* @date 2019年5月12日 下午9:56:22
*/
public class HDmapHolding extends HDmap implements FSmapHolding{

	public HDmapHolding(Path filePath, long capacity) {
		super(filePath, capacity);
	}
	
	@Override
	protected boolean isHolding(KeyShell key) {
		return holding(getRelativPath(key));
	}
	@Override
	protected boolean isHolding(Path file) {
		return holding(getRelativPath(file));
	}

	private Path getRelativPath(KeyShell key) {
		String dir = encodeDir(key);
		Path d = filePath.resolve(dir);
		Path f = d.resolve(encodeFilename(key));
		return filePath.relativize(f);
	}
	private Path getRelativPath(Path file) {
		return filePath.relativize(file);
	}
	
	protected boolean holding(Path relativePath) {
		return holdmap.get(relativePath)!=null;
	}

	
	
	Map<Path, Object> holdmap = Collections.synchronizedMap(new HashMap<Path, Object>()); 
	
	Map<Path, Set<Object>> muiltiholdmap = new HashMap<>();
	
	@Override
	public void addHold(Object lock,KeyShell... keys) {
		ArrayList<Path> m = new ArrayList<Path>(keys.length);
		for (KeyShell k : keys) {
			m.add(getRelativPath(k));
		}
		if(m.size()>0) {
			synchronized (holdmap) {
				for (Path p : m) {
					//Pblog.print("TEST", "new Path ",p);
					Object oldlock = holdmap.putIfAbsent(p, lock);
					if(oldlock!=null && oldlock!=lock) {
						if(oldlock==muiltiholdmap) {
							Set<Object> set = muiltiholdmap.get(p);
							set.add(lock); //set此时不应该为Null;
						}else{
							HashSet<Object> set = new HashSet<>(2);
							set.add(oldlock);
							set.add(lock);
							muiltiholdmap.put(p,set); //muiltimap此时不应该有数据;
							holdmap.put(p,muiltiholdmap);
						}
					}
				}
			}
		}
	}
	@Override
	public void removeHold(Object lock) {
		synchronized (holdmap) {
			Iterator<Map.Entry<Path, Object>> it = holdmap.entrySet().iterator();
			while(it.hasNext()) {
				Map.Entry<Path, Object> entry = it.next();
				Object v = entry.getValue();
				if(v==lock) {
					it.remove();
				}else if(v==muiltiholdmap) {
					Set<Object> set = muiltiholdmap.get(entry.getKey());
					if(set==null) {
						it.remove();
					}else{
						set.remove(lock);
						if(set.isEmpty()) {
							muiltiholdmap.remove(entry.getKey());
							it.remove();
						}
					}
				}
			}
		}
	}
	@Override
	public int holdSize() {
		return holdmap.size();
	}
	@Override
	public long capacity() {
		try {
			return super.capacity();
		} catch (IOException e) {
			if(Pblog.FS)Pblog.FS(e);
		}
		return 0;
	}
}
